#include "qutils.h"

#include <QProcess>
#include <QDebug>
#include <QLayoutItem>
#include <QLayout>
#include <QSystemSemaphore>
#include <QSharedMemory>
#include <QMessageBox>
#include <QApplication>
#include <QPushButton>

bool QUtils::check_command_exists(const QString &command) {
    QProcess process;
    process.start("which", QStringList() << command);
    process.waitForFinished();
    return process.exitCode() == 0;
}

QByteArray QUtils::get_command_output(const QString &command) {
    QProcess process;
    process.start(command);
    process.waitForFinished();
    return process.readAllStandardOutput();
}

QByteArray QUtils::get_command_output(const QStringList &commands) {
    QProcess process;
    process.start(commands.first(), commands.mid(1));
    process.waitForFinished();
    return process.readAllStandardOutput();
}

QStringList QUtils::qstring_to_list(const QString &str) {
    return str.split('\n');
}

QStringList QUtils::qstring_to_no_empty_list(const QString &str) {
    QStringList list;
    for (auto line : qstring_to_list(str)) {
        line = line.trimmed();
        if (line.isEmpty()) {
            continue;
        }
        list << line;
    }
    return list;
}

QStringList QUtils::get_tar_gz_list(const QString &targz_filename) {
    if (!check_command_exists("tar")) {
        qDebug() << "tar command not found";
        return QStringList();
    }

    QStringList commands;
    commands << "tar" << "-ztf" << targz_filename;

    QByteArray output = get_command_output(commands);

    return qstring_to_no_empty_list(output);
}

void QUtils::qwidget_delete_childrens(QWidget *parent)
{
    if (parent->layout() == nullptr) {
        return;
    }

    while (QLayoutItem *item = parent->layout()->takeAt(0))
    {
        delete item->widget();
        delete item;
    }
}


bool QUtils::qsystem_semaphore_lock(const QString &name, bool by_gui)
{
    // 创建信号量
    // 启用信号量，禁止其他实例通过共享内存一起工作
    QSystemSemaphore *semaphore = new QSystemSemaphore(name + " Semaphore", 1);
    semaphore->acquire();

    //  在linux / unix 中程序异常结束共享内存不会回收
    // 在这里需要提供释放内存的接口，就是在程序运行的时候如果有这段内存 先清除掉
    QSharedMemory nix_fix_shared_memory(name);
    if (nix_fix_shared_memory.attach())
    {
        nix_fix_shared_memory.detach();
    }

    // 创建一个共享内存  “name”表示一段内存的标识 key 可作为唯一程序的标识，并测试是否已经运行，
    bool isRunning = false;
    QSharedMemory *sharedMemory = new QSharedMemory(name);
    std::make_shared<QSharedMemory>(sharedMemory);
    // 试图将共享内存的副本附加到现有的段中。
    if (sharedMemory->attach()) {
        // 如果成功，则确定已经存在运行实例
        isRunning = true;
    }else{
        // 否则申请一字节内存
        sharedMemory->create(1);
        // 确定不存在运行实例
        isRunning = false;
    }
    semaphore->release();

    // 如果您已经运行了应用程序的一个实例，那么将通知用户。
    if(isRunning) {
        if (by_gui) {
            QMessageBox infomationMsgBox;
            infomationMsgBox.setIcon(QMessageBox::Warning);
            infomationMsgBox.setWindowTitle(QObject::tr("温馨提示"));
            infomationMsgBox.setText(qApp->applicationDisplayName() + "\n在当前用户已经打开，请不要重复打开！");

            QPushButton *stillButton = infomationMsgBox.addButton(QMessageBox::Yes);
            QPushButton *closeButton = infomationMsgBox.addButton(QMessageBox::Cancel);
            stillButton->setText(QObject::tr("仍然打开"));
            closeButton->setText(QObject::tr("关闭"));

            infomationMsgBox.setDefaultButton(closeButton);
            infomationMsgBox.exec();

            if (infomationMsgBox.clickedButton() == (QAbstractButton*)closeButton) {
                return false;
            }
        }
    }

    return true;
}
